package org.apache.osgimaker.analyse.algorithm.graph;

import java.util.Vector;

/**
 *  The base class for any type of vertex in a directed graph.
 *  <p>
 *  A <tt>Vertex</tt> holds an {@link Attributes} object which encapsulates
 *  all properties of the vertex which are not necessary to know for
 *  parsing a graph in a {@link GraphProcessor}. Only the visited flag will
 *  be manipulated during parsing.
 *  <p>
 *  A <tt>Vertex</tt> knows the head and tail vertices of all its outgoing
 *  and incoming arcs. When a head vertex is added by the method
 *  {@link #addOutgoingArcTo} also the corresponding incoming arc is built
 *  in the head vertex. The same is true the other way around. Note,
 *  that multi-arcs are not possible. That is, adding an already added
 *  head/tail vertex again as a head/tail vertex will be ignored.
 *
 */
public class Vertex implements Comparable 
{
  private final Vector _heads = new Vector();
  private final Vector _tails = new Vector();
  private final Attributes _attributes;
  private boolean _visited;

  /** Create a new instance for the specified attributes. */
  public Vertex(Attributes attributes) 
  {
    _attributes = attributes;
  }

  /** Returns the attributes. */
  public Attributes getAttributes() 
  {
    return _attributes;
  }

  /**
   * Returns the number of outgoing arcs. This is equivalent to the number
   * of head vertices.
   */
  public int getNumberOfOutgoingArcs() 
  {
    return _heads.size();
  }

  /** Returns the head vertex of the specified outgoing arc. */
  public Vertex getHeadVertex(int index) 
  {
    return (Vertex) _heads.elementAt(index);
  }

  /**
   * Adds an outgoing arc to the specified vertex. Also calls
   * {@link #addIncomingArcTo} for <tt>headVertex</tt> with <tt>this</tt> as
   * the argument. Does nothing if <tt>headVertex</tt> is the head
   * vertex of an already existing outgoing arc.
   * @param headVertex Head vertex to be added to establish a new outgoing arc.
   *        <tt>Null</tt> is not allowed.
   */
  public void addOutgoingArcTo(Vertex headVertex) 
  {
    if (!_heads.contains(headVertex)) 
    {
      _heads.addElement(headVertex);
      headVertex.addIncomingArcTo(this);
    }
  }

  /**
   * Returns the number of incoming arcs. This is equivalent to the number
   * of tail vertices.
   */
  public int getNumberOfIncomingArcs() 
  {
    return _tails.size();
  }

  /** Returns the tail vertex of the specified outgoing arc. */
  public Vertex getTailVertex(int index) 
  {
    return (Vertex) _tails.elementAt(index);
  }

  /**
   * Adds an incoming arc to the specified vertex. Also calls
   * {@link #addOutgoingArcTo} for <tt>tailVertex</tt> with <tt>this</tt> as
   * the argument. Does nothing if <tt>tailVertex</tt> is the
   * tail vertex of an already existing incoming arc.
   * @param tailVertex Tail vertex to be added to establish a new incoming arc.
   *        <tt>Null</tt> is not allowed.
   */
  public void addIncomingArcTo(Vertex tailVertex) 
  {
    if (!_tails.contains(tailVertex)) 
    {
      _tails.addElement(tailVertex);
      tailVertex.addOutgoingArcTo(this);
    }
  }

  /** Reset this vertex. That is, the visited flag is set to <tt>false</tt>. */
  public void reset() 
  {
    _visited = false;
  }

  /**
   *  Marks this instance as visited.
   *  That is, the visited flag becomes <tt>true</tt>.
   */
  public void visit() 
  {
    _visited = true;
  }

  /** Returns the visited flag. */
  public boolean isVisited() 
  {
    return _visited;
  }

  /**
   *  Returns <tt>toString()</tt> of the attributes and the number of
   *  incoming and outgoing arcs.
   */
  public String toString() 
  {
    StringBuffer result = new StringBuffer();
    result.append(getAttributes() == null ? super.toString() 
                                          : getAttributes().toString())
          .append(": ").append(getNumberOfIncomingArcs())
          .append(" incoming arc(s), ").append(getNumberOfOutgoingArcs())
          .append(" outgoing arc(s).");
    return new String(result);
  }

  public int compareTo(Object object)
  {
    int result = 1;
    if (object instanceof Vertex && _attributes != null)
    {
      result = _attributes.compareTo(((Vertex) object)._attributes);
    }
    return result;
  }

} //class